interface IData<T> {
  [index: number]: T
}

class Dequeue<T> {
  count: number
  lowerestCount: number
  items: IData<T>

  constructor() {
    this.count = 0
    this.lowerestCount = 0
    this.items = {}
  }

  // 该方法在双端队列前端添加新的元素。
  addFront(element: T | T[]): void {
    if (this.isEmpty()) {
      // 队列为空
      this.addBack(element)
    } else {
      // 队列非空
      if (!(element instanceof Array)) {
        this.items[this.lowerestCount--] = element
      } else {
        const len = element.length
        let tailIndex = len - 1
        while (tailIndex >= 0) {
          this.items[this.lowerestCount--] = element[tailIndex--]
        }
      }
    }
  }
  // 该方法在双端队列后端添加新的元素(实现方法和 Queue 类中的 enqueue 方法相同)。
  addBack(element: T | T[]): void {
    if (this.isEmpty()) {
      // 队列为空
      if (!(element instanceof Array)) {
        this.items[this.count++] = element
      } else {
        for (let i = 0; i < element.length; i++) {
          this.items[this.count++] = element[i]
        }
      }
      this.lowerestCount--
    } else {
      // 队列非空
      if (!(element instanceof Array)) {
        this.items[this.count++] = element
      } else {
        for (let i = 0; i < element.length; i++) {
          this.items[this.count++] = element[i]
        }
      }
    }
  }
  // 该方法会从双端队列前端移除第一个元素(实现方法和 Queue 类中的 dequeue 方法相同)。
  removeFront(): T | undefined {
    if (this.isEmpty()) {
      return undefined
    } else {
      const front = this.items[this.lowerestCount + 1]
      delete this.items[this.lowerestCount + 1]
      this.lowerestCount++
      return front
    }
  }
  // 该方法会从双端队列后端移除第一个元素(实现方法和 Stack 类中的 pop 方法一样)。
  removeBack(): T | undefined {
    if (this.isEmpty()) {
      return undefined
    } else {
      const tail = this.items[this.count - 1]
      delete this.items[this.count - 1]
      this.count--
      return tail
    }
    return
  }
  // 该方法返回双端队列前端的第一个元素(实现方法和 Queue 类中的 peek 方法一样)。
  peekFront(): T | undefined {
    if (!this.isEmpty()) {
      // 非空
      return this.items[this.lowerestCount + 1]
    } else {
      return undefined
    }
  }
  // 该方法返回双端队列后端的第一个元素(实现方法和 Stack 类中的 peek 方法一样)。
  peekBack(): T | undefined {
    if (!this.isEmpty()) {
      // 非空
      return this.items[this.count - 1]
    } else {
      return undefined
    }
  }

  isEmpty(): boolean {
    return this.size() === 0
  }
  // 返回队列包含的元素个数，与数组的 length 属性类似。
  size(): number {
    const distance = this.count - this.lowerestCount - 1
    return distance > 0 ? distance : 0
  }
  // 清空队列
  clear(): void {
    this.lowerestCount = 0
    this.count = 0
    this.items = {}
  }
  // 创建 toString 方法
  toString(): string {
    if (this.isEmpty()) {
      return ''
    }
    let lowerestCount = this.lowerestCount
    let ret: string = this.items[++lowerestCount] + ''
    while (lowerestCount < this.count - 1) {
      ret = `${ret},${this.items[++lowerestCount]}`
    }
    return ret
  }
}

export default Dequeue

/**
 *
 * 如果思路卡住了

那么是在哪个点卡住了

如果是单向队列
则索引模型是
  如果是空队列则：
    lowerCount === count
    lowerCount === undefined
    count === undefined
  如果是非空队列
    lowerCount !== count
    lowerCount !== undefined
    count === undefined
  队列长度计算方法
    size = count - lowerCount

如果是单向队列
则索引模型是
  如果是空队列则：
    lowerCount === count
    lowerCount === undefined
    count === undefined
  如果是非空队列
    lowerCount !== count
    lowerCount === undefined
    count === undefined
    index  !== undefined (lowerCount < index < count)
  队列长度计算方法
    size = count - lowerCount (空队列)
    size = count - lowerCount - 1 （非空队列）
    size = count - lowerCount - 1 > 0 ? count - lowerCount - 1 : 0
 */
